package com.easpeed.comon.photo

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.database.Cursor
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.media.ExifInterface
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.Environment.DIRECTORY_PICTURES
import android.provider.MediaStore
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import com.blankj.utilcode.util.FileUtils
import java.io.File
import java.io.IOException

class PhotoUtils(var mContext: Context) {

    val CROP_RESULT_CODE = 10002
    val TAKE_PHOTO = 10003
    val CROP_PHOTO = 10004
    val MULT_PHOTO = 10005

    private var avoidOnResult: AvoidOnResult? = null

    private var callback: AvoidOnResult.Callback? = null
    val fileProvider = ".fileProvider"

    /**
     * 应用包名
     */
    private var packageName: String = ""

    /**
     * 是否裁剪
     */
    private var mIsCrop: Boolean = false

    private var currentCropStyle = CROP_1


    private var currentFile: File? = null

    private var cropFile: File? = null

    init {
        currentFile = getFile()
        packageName = mContext.packageName
        var fragmentManager: FragmentManager? = null
        if (mContext is Fragment) {
            fragmentManager = (mContext as Fragment).childFragmentManager
        } else {
            fragmentManager = (mContext as FragmentActivity).supportFragmentManager
        }
        cropFile =
            File(Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES), "${System.currentTimeMillis()}crop_image.jpg")
        avoidOnResult = AvoidOnResult(fragmentManager)
    }

    companion object {
        /**
         * 矩形裁剪
         */
        const val CROP_1 = "CROP_1"

        /**
         * 正方形裁剪
         */
        const val CROP_CIRCLE = "CROP_CIRCLE"
    }

    public fun setIsCrop(mIsCrop: Boolean) {
        this.mIsCrop = mIsCrop
    }

    public fun setCurrentCropStyle(currentCropStyle: String) {
        this.currentCropStyle = currentCropStyle
    }

    fun setCallback(callback: AvoidOnResult.Callback?) {
        this.callback = callback
    }

    /**
     * 拍照
     */
    fun startCamera() {
        val uri = getUri(currentFile!!)
        val capture: Intent = getCapture(uri!!)
        avoidOnResult!!.startForResult(capture, TAKE_PHOTO, callback)
    }


    /**
     * 相册选择
     */
    fun choosePic() {
        // 来自相册
        val intent = Intent(Intent.ACTION_PICK, null)
        /**
         * 下面这句话，与其它方式写是一样的效果，如果：
         * intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
         * intent.setType(""image/ *");设置数据类型
         * 要限制上传到服务器的图片类型时可以直接写如："image/jpeg 、 image/png等的类型"
         */
        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
        //        ((AppCompatActivity) context).startActivityForResult(intent, CROP_PHOTO);
        avoidOnResult!!.startForResult(intent, CROP_PHOTO, callback)
    }


    private fun getFile(): File {
        val fileName = "${System.currentTimeMillis()}_img"
        val suffix = ".jpg"
        val path = "${getCrashDir(mContext)}"
        return File.createTempFile(fileName, suffix, File(path))
    }

    private fun getCrashDir(context: Context?): File? {
        val dir: File? = context?.getExternalFilesDir("photo")
        FileUtils.createOrExistsDir(dir)
        return dir
    }

    private fun getUri(currentFile: File): Uri? {
        val uri: Uri? = if (isSDKN()) {
            FileProvider.getUriForFile(mContext, packageName + fileProvider, currentFile)
        } else {
            Uri.fromFile(currentFile)
        }
        return uri
    }


    /**
     * 在onActivityResult 中调用这个函数
     *
     * @param photoResult 返回bitmap回调
     */
    fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?, photoResult: PhotoResult?) {
        //拍照返回
        if (requestCode == TAKE_PHOTO && resultCode == Activity.RESULT_OK) {
            val uri = getUri(currentFile!!)
            if (mIsCrop) {  //裁剪照片
                cropPic(uri, true)
            } else {
                val photo = BitmapFactory.decodeFile(currentFile!!.absolutePath)
                val degree: Int = getBitmapDegree(currentFile!!.absolutePath)
                val bitmap: Bitmap? = rotateBitmapByDegree(photo, degree)
                photoResult?.photoResult(bitmap)
            }
        } else if (requestCode == CROP_RESULT_CODE && data != null) {
            //裁剪图片返回
            val photo = BitmapFactory.decodeFile(cropFile!!.absolutePath)
            val degree: Int = getBitmapDegree(cropFile!!.absolutePath)
            val bitmap: Bitmap? = rotateBitmapByDegree(photo, degree)
            photoResult?.photoResult(bitmap)
        } else if (requestCode == CROP_PHOTO && resultCode == Activity.RESULT_OK) {
            if (mIsCrop) {
                // 使用裁剪功能情况
                val uri = data!!.data
                cropPic(uri, false)
            } else {
                //不使用用裁剪功能
                try {
                    //获取系统返回的照片的Uri
                    val selectedImage = data!!.data
                    val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
                    //从系统表中查询指定Uri对应的照片
                    val cursor: Cursor? = mContext.contentResolver.query(selectedImage!!, filePathColumn, null, null, null)
                    var bitmap: Bitmap? = null
                    if (cursor != null) {
                        cursor.moveToFirst()
                        val columnIndex = cursor.getColumnIndex(filePathColumn[0])
                        //获取照片路径
                        val path = cursor.getString(columnIndex)
                        cursor.close()
//                        bitmap = BitmapFactory.decodeFile(path)

                        val photo = BitmapFactory.decodeFile(path)
                        val degree: Int = getBitmapDegree(path)
                         bitmap= rotateBitmapByDegree(photo, degree)
                    }
                    photoResult?.photoResult(bitmap)
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }
    }


    /**
     * 裁剪图片
     */
    private fun cropPic(data: Uri?, isTakePhoto: Boolean) {
        if (data == null) {
            return
        }
        val cropIntent = Intent("com.android.camera.action.CROP")
        if (isSDKN()) {
            cropIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        }
        cropIntent.setDataAndType(data, "image/*")
        cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, data);

        // 开启裁剪：打开的Intent所显示的View可裁剪
        cropIntent.putExtra("crop", "true")

        if (currentCropStyle == CROP_1) {

            // 裁剪宽高比
            cropIntent.putExtra("aspectX", 3)
            cropIntent.putExtra("aspectY", 2)
            // 裁剪输出大小
//            cropIntent.putExtra("outputX", 740)
//            cropIntent.putExtra("outputY", 520)
        } else {

            // 裁剪宽高比
            cropIntent.putExtra("aspectX", 1)
            cropIntent.putExtra("aspectY", 1)
            // 裁剪输出大小
//            cropIntent.putExtra("outputX", 400)
//            cropIntent.putExtra("outputY", 400)
        }
        cropIntent.putExtra("scale", true)
        cropIntent.putExtra("scaleUpIfNeeded", true) //黑边

        /**
         * return-data
         * 这个属性决定我们在 onActivityResult 中接收到的是什么数据，
         * 如果设置为true 那么data将会返回一个bitmap
         * 如果设置为false，则会将图片保存到本地并将对应的uri返回，当然这个uri得有我们自己设定。
         * 系统裁剪完成后将会将裁剪完成的图片保存在我们所这设定这个uri地址上。我们只需要在裁剪完成后直接调用该uri来设置图片，就可以了。
         */
        cropIntent.putExtra("return-data", false)
        // 当 return-data 为 false 的时候需要设置这句
        cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cropFile));
        // 图片输出格式
        cropIntent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        // 头像识别 会启动系统的拍照时人脸识别
        //        cropIntent.putExtra("noFaceDetection", true);
        avoidOnResult!!.startForResult(cropIntent, CROP_RESULT_CODE, callback)
    }


    /**
     * @return 判断当前是否android 7.0
     */
    private fun isSDKN(): Boolean {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
    }

    /**
     * 获取拍照Intent
     */
    private fun getCapture(outPutUri: Uri): Intent {
        val intent = Intent()
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        intent.action = MediaStore.ACTION_IMAGE_CAPTURE //设置Action为拍照
        intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutUri) //将拍取的照片保存到指定URI
        return intent
    }


    interface PhotoResult {
        fun photoResult(bitmap: Bitmap?)
    }


    /**
     * 读取图片的旋转的角度
     *
     * @param path 图片绝对路径
     * @return 图片的旋转角度
     */
    private fun getBitmapDegree(path: String): Int {
        var degree = 0
        try {
            // 从指定路径下读取图片，并获取其EXIF信息
            val exifInterface = ExifInterface(path)
            val orientation =
                exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
            when (orientation) {
                ExifInterface.ORIENTATION_ROTATE_90 -> degree = 90
                ExifInterface.ORIENTATION_ROTATE_180 -> degree = 180
                ExifInterface.ORIENTATION_ROTATE_270 -> degree = 270
                else -> {
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return degree
    }

    /**
     * 将图片按照某个角度进行旋转
     *
     * @param bm     需要旋转的图片
     * @param degree 旋转角度
     * @return 旋转后的图片
     */
    fun rotateBitmapByDegree(bm: Bitmap, degree: Int): Bitmap? {
        var returnBm: Bitmap? = null
        // 根据旋转角度，生成旋转矩阵
        val matrix = Matrix()
        matrix.postRotate(degree.toFloat())
        try {
            // 将原始图片按照旋转矩阵进行旋转，并得到新的图片
            returnBm = Bitmap.createBitmap(bm, 0, 0, bm.width, bm.height, matrix, true)
        } catch (e: OutOfMemoryError) {

        }
        if (returnBm == null) {
            returnBm = bm
        }
        if (bm != returnBm) {
            bm.recycle()
        }
        return returnBm
    }
}